package com.example.guard_toollib;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class ZipUtil {


    public static void main(String[] args) {

        File directory = new File("security-tool_lib\\test");
        unZip(new File("security-tool_lib\\oldApp.apk"), directory);

//        zip(directory, new File("security-tool_lib\\aaa1.zip"));
    }

    /**
     * 解压到指定目录
     *
     * @param zip
     * @param detFolder
     */
    public static void unZip(File zip, File detFolder) {
        if (detFolder.exists()) {
            cleanDirectory(detFolder);
        } else {
            if (!detFolder.mkdirs())
                throw new RuntimeException("Failed created folder:" + detFolder.getAbsolutePath());
        }
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(zip);
            Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
            while (zipEntries.hasMoreElements()) {//目录/文件名  所有文件
                ZipEntry zipEntry = zipEntries.nextElement();
                String name = zipEntry.getName();
                //原来的签名文件 不需要了
                if (name.equals("META-INF/MANIFEST.MF") || name.equals("META-INF/CERT.SF") || name.equals("META-INF/CERT.RSA")) {
                    continue;
                }
                //空目录不管
                if (!zipEntry.isDirectory()) {
                    File file = new File(detFolder, name);
                    //创建目录
                    if (!file.getParentFile().exists()) {
                        if (!file.getParentFile().mkdirs())
                            throw new RuntimeException("Failed created folder:" + file.getParent());
                    }
                    //写文件
                    try (FileOutputStream fos = new FileOutputStream(file);
                         InputStream is = zipFile.getInputStream(zipEntry)) {
                        byte[] buffer = new byte[2048];
                        int len;
                        while ((len = is.read(buffer)) != -1) {
                            fos.write(buffer, 0, len);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (zipFile != null)
                try {
                    zipFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }

    }


    /**
     * 压缩指定目录
     *
     * @param srcFolder
     * @param zip 压缩后文件
     */
    public static void zip(File srcFolder, File zip) {
        if (zip.exists()) {
            if (zip.delete()) {
                throw new RuntimeException("zip Failed delete file:" + zip.getAbsolutePath());
            }
        }
        // 对输出文件做CRC32校验
        CheckedOutputStream cos = null;
        try {
            cos = new CheckedOutputStream(new FileOutputStream(zip), new CRC32());
            try (ZipOutputStream zos = new ZipOutputStream(cos)) {
                //压缩
                compress(srcFolder, zos, "");
                zos.flush();
                zos.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 添加目录/文件 至zip中
     *
     * @param srcFile  需要添加的目录/文件
     * @param zos      zip输出流
     * @param basePath 递归子目录时的完整目录 如 lib/x86
     * @throws Exception
     */
    private static void compress(File srcFile, ZipOutputStream zos,
                                 String basePath) throws Exception {
        if (srcFile.isDirectory()) {
            File[] files = srcFile.listFiles();
            for (File file : files) {
                // zip 递归添加目录中的文件
                compress(file, zos, basePath + srcFile.getName() + "/");
            }
        } else {
            compressFile(srcFile, zos, basePath);
        }
    }

    private static void compressFile(File file, ZipOutputStream zos, String dir)
            throws Exception {
        // temp/lib/x86/libdn_ssl.so
        String fullName = dir + file.getName();
        // 需要去掉temp
        String[] fileNames = fullName.split("/");
        //正确的文件目录名 (去掉了temp)
        StringBuilder sb = new StringBuilder();
        if (fileNames.length > 1) {
            for (int i = 1; i < fileNames.length; ++i) {
                sb.append("/");
                sb.append(fileNames[i]);
            }
        } else {
            sb.append("/");
        }
        //添加一个zip条目
        ZipEntry entry = new ZipEntry(sb.substring(1));
        zos.putNextEntry(entry);
        //读取条目输出到zip中
        try (FileInputStream fis = new FileInputStream(file)) {
            int len;
            byte data[] = new byte[2048];
            while ((len = fis.read(data, 0, 2048)) != -1) {
                zos.write(data, 0, len);
            }
            fis.close();
            zos.closeEntry();
        }
    }

    /***
     *  Cleans a directory without deleting it.
     * @param directory
     */
    public static void cleanDirectory(File directory) {
        if (!directory.exists() || !directory.isDirectory()) {
            throw new RuntimeException("not exists or is not a directory:" + directory.getAbsolutePath());
        }
        final File[] files = directory.listFiles();
        if (files == null)
            throw new RuntimeException("Failed to list contents of :" + directory.getAbsolutePath());

        for (File file : files) {
            if (file.isDirectory()) {
                cleanDirectory(file);
            }
            if (!file.delete()) {
                throw new RuntimeException("Failed to delete:" + file.getAbsolutePath());
            }
        }

    }


}
